<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 * @author   howe <howe1995@163.com>
 */

namespace App\Repository;

use App\Constant\ApiCodeEnum;
use App\Constant\Database\UserEnum;
use App\Exception\BusinessException;
use App\Model\MoneyFlowLog;
use App\Model\User;
use Exception;
use Hyperf\DbConnection\Db;

/**
 * User 数据层
 */
class UserRepository extends User
{
    /**
     * 获取消息未读数.
     */
    public static function getUnreadById(int $id): array
    {
        $user = self::query()->find($id, ['unread']);
        return $user->unread;
    }

    /**
     * 增加信息未读数.
     * @param mixed $num
     */
    public static function incrUnread(array $ids, string $field, int $from = 0, $num = 1): int
    {
        if (empty($ids)) {
            return 0;
        }
        if ($field == 'moment.num') {
            self::query()->whereIn('id', $ids)->update([
                'unread' => Db::raw("JSON_SET(unread, '$.moment.from', {$from})"),
            ]);
        }
        return self::query()->whereIn('id', $ids)->update([
            'unread' => Db::raw("JSON_SET(unread, '$.{$field}', JSON_EXTRACT(unread, '$.{$field}') + {$num})"),
        ]);
    }

    /**
     * 清空消息未读数.
     */
    public static function clearUnread(array $ids, string $field): int
    {
        return self::query()->whereIn('id', $ids)->update([
            'unread' => Db::raw("JSON_SET(unread, '$.{$field}', 0)"),
        ]);
    }

    public static function checkExistsBySetting(int $userId, string $column, string $value): bool
    {
        return self::query()->where('id', $userId)->whereRaw("JSON_EXTRACT(setting, '$.{$column}') = '{$value}'")->exists();
    }

    /**
     * 充值
     * @throws BusinessException
     */
    public static function changeMoney(int|object $userId, string $money, string $type = UserEnum::MONEY_INCR, array $extend = []): void
    {
        Db::beginTransaction();
        try {
            if (is_int($userId)) {
                $user = self::query()->findOrFail($userId);
            } else {
                $user = $userId;
            }
            $money = $money * 100;
            $beforeMoney = $user->money;
            if ($type === UserEnum::MONEY_INCR) {
                $user->money = $user->money + $money;
            } elseif ($type === UserEnum::MONEY_DECR) {
                if ($money * 100 > $user->money) {
                    throw new BusinessException(ApiCodeEnum::SERVICE_ACCOUNT_MONEY_NOT_ENOUGH);
                }
                $user->money = $user->money - $money;
            }
            $afterMoney = $user->money;
            if ($user->save() && isset($extend['money_flow_type'])) {
                $data = [
                    'type' => $extend['money_flow_type'],
                    'from_id' => $extend['from_id'] ?? 0,
                    'user_id' => $user->id,
                    'before_money' => $beforeMoney,
                    'after_money' => $afterMoney,
                    'money' => $money,
                    'remark' => $extend['remark'] ?? '',
                    'created_at' => time(),
                ];
                MoneyFlowLog::query()->insert($data);
            }
            Db::commit();
        } catch (Exception $e) {
            Db::rollBack();
            throw new BusinessException(ApiCodeEnum::SYSTEM_ERROR, $e->getMessage());
        }
    }
}
